/*
 *  $Id: Abstract.cs 1130 2010-09-29 11:57:53Z thenn.erannor $
 *  This file is a part of Ragima CCG.
 *  (C) 2008 Ragima development group.
 *
 *  Licensed under the terms of the GNU GPL License version 2.
 *
 */

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

using AgateLib.DisplayLib;
using AgateLib.Geometry;

namespace Ragima {
    /// <summary>
    /// Абстрактный эффект (конкретные эффекты должны давать его наследники)
    /// </summary>
    public abstract class Affect: IHelpProvider, IDescriptionSource {
        public const string AffectPrefix = "affect.";

        private AffectInfo _info;
        private AbstractObject _owner;
        private CardDescription _drawDesc;

        /// <value>
        /// Идентификатор эффекта, используемый по умолчанию для идентификаторов ресурсов.
        /// </value>
        public abstract string Id { get; }

        /// <value>
        /// Дополнительная информация об эффекте
        /// </value>
        public AffectInfo Info {
            get { return _info ?? (_info = AffectManager.GetInfo(this)); }
        }

        /// <value>
        /// Название эффекта
        /// </value>
        public virtual Languages.Phrase Name {
            get { return Info.Name; }
        }
        /// <value>
        /// Название эффекта в виде строки
        /// </value>
        public virtual string NameText { get { return Name != null ? Name.GetText() : string.Empty; } }

        /// <value>
        /// Стихия, к которой относится эффект (для цвета рамки)
        /// </value>
        public virtual ElementType Element { get { return ElementType.Neutral; } }

        /// <value>
        /// Описание эффекта
        /// </value>
        public virtual Languages.Phrase Description {
            get { return Info.Description; }
        }

        /// <value>
        /// Описание эффекта в виде строки
        /// </value>
        public virtual string DescriptionText { get { return Description != null ? Description.GetText() : string.Empty; } }

        /// <value>
        /// Базовый вес эффекта
        /// </value>
        public virtual int BaseWeight {
            get { return 0; }
        }

        /// <summary>
        /// Запрос веса эффекта
        /// </summary>
        public virtual int GetWeight(Card card) {
            int weight = BaseWeight;
            if (Element != ElementType.Neutral) {
                switch (Element.GetRelationTo(card.Element)) {
                    case ElementRelation.Enemy:
                        weight = weight * WeightCoeff.AffectEnemyPercent / 100;
                        break;
                    case ElementRelation.Other:
                        weight = weight * WeightCoeff.AffectOtherPercent / 100;
                        break;
                }
            }
            return weight;
        }

        /// <value>
        /// Индекс иконки эффекта
        /// </value>
        public virtual AffectIcon Icon {
            get { return AffectIcon.None; }
        }
        //// <value>
        /// Наличие иконки эффекта
        /// </value>
        public bool HasIcon {
            get { return Icon != AffectIcon.None; }
        }

        /// <summary>
        /// Список иконок эффекта, обычно ноль или одна текущая.
        /// </summary>
        public virtual IEnumerable<AffectIcon> GetIcons() {
            if (HasIcon) yield return Icon;
        }

        /// <summary>
        /// Список эффектов с иконками, обычно ноль или один текущий.
        /// </summary>
        public virtual IEnumerable<Affect> GetIconAffects() {
            if (HasIcon) yield return this;
        }

        /// <value>
        /// Описание эффекта, показываемое на его иконке.
        /// </value>
        public virtual Languages.Phrase IconDescription {
            get { return Info.IconDescription; }
        }
        /// <value>
        /// Описание эффекта, показываемое на его иконке, в виде строки.
        /// </value>
        public virtual string IconDescriptionText {
            get { return IconDescription != null ? IconDescription.GetText() : string.Empty; }
        }

        /// <value>
        /// Большое изображение эффекта
        /// </value>
        public virtual Surface BigPicture {
            get { return Info.BigPicture; }
        }

        /// <value>
        /// Маленькое изображение эффекта
        /// </value>
        public virtual Surface SmallPicture {
            get { return Info.SmallPicture; }
        }

        /// <value>
        /// Имеет ли эффект изображения
        /// </value>
        public virtual bool Drawable { get { return SmallPicture != null; } }

        /// <value>
        /// Может ли эффект быть развеян
        /// </value>
        public virtual bool Dispellable { get { return true; } }

        /// <value>
        /// Завершен ли эффект (нужно ли его удалять)
        /// </value>
        public virtual bool IsEnded { get { return false; } }

        /// <value>
        /// Владелец эффекта
        /// </value>
        public virtual AbstractObject Owner {
            get { return _owner; }
            set { _owner = value; }
        }

        /// <summary>
        /// Является ли эффект корневым
        /// </summary>
        public bool IsRoot {
            get { return Owner != null && Owner.HasAffect(this); }
        }

        /// <value>
        /// Локальный суммарный эффект
        /// </value>
        public AffectSummary LocalSummary {
            get { return _owner != null ? _owner.Summary : null; }
        }

        /// <value>
        /// Глобальный суммарный эффект
        /// </value>
        public AffectSummary GlobalSummary {
            get { return _owner != null ? _owner.GlobalSummary : null; }
        }

        /// <value>
        /// Глобальный вражеский суммарный эффект
        /// </value>
        public AffectSummary EnemySummary {
            get { return _owner != null ? _owner.EnemySummary : null; }
        }

        /// <summary>
        /// Клонирование эффекта (создание нового эффекта этого же типа)
        /// </summary>
        /// <returns>Созданный эффект</returns>
        public virtual Affect Clone() {
            return (Affect) Activator.CreateInstance(GetType());
        }

        /// <summary>
        /// Удаление установленного эффекта
        /// </summary>
        public void Remove() {
            if (_owner != null) _owner.RemoveAffect(this);
        }

        /// <summary>
        /// Рассеивание эффекта
        /// </summary>
        public virtual void Dispell() {
            Remove();
        }

        /// <summary>
        /// Некоторые действия при снятии эффекта
        /// </summary>
        public virtual void OnRemove() { }

        /// <summary>
        /// Установка действия эффекта
        /// </summary>
        public virtual void SetAffect() {
            if (Drawable) LocalSummary.AddEnchantment(this);
            if (HasIcon) LocalSummary.Icons.Add(this);
        }

        /// <summary>
        /// Снятие действия эффекта
        /// </summary>
        public virtual void ResetAffect() {
            if (Drawable) LocalSummary.RemoveEnchantment(this);
            if (HasIcon) LocalSummary.Icons.Remove(this);
        }

        public virtual bool DrawHelp(int x, int y) {
            return DrawHelpDefault(x, y);
        }
        protected bool DrawHelpDefault(int x, int y) {
            if (BigPicture != null) BigPicture.Draw(x+16, y+25);
            Element.Frame.Draw(x, y);
            Data.Fonts.CardName.Color = Color.Black;
            Data.Fonts.CardName.DrawCenter(x+150, y+4, NameText);
            DrawDescription(x+20, y+314);
            return true;
        }
        private void DrawDescription(int x, int y) {
            if (_drawDesc == null)
                _drawDesc = new CardDescription(this, Constants.HelpDescriptionWidth);
            _drawDesc.Draw(x, y);
        }

        protected void UpdateDescription() {
            if (_drawDesc != null)
                _drawDesc.Update();
        }

        public DamageInfo NewDamage(DamageType dmgType, int damage) {
            return new AffectDamageInfo(this, dmgType, damage);
        }
    }
}
